# v1.0 单个文件的传输
import os
import socket
import threading
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from queue import Queue

class TransferGUI:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("内网极速传文件 v1.0")
        self.setup_ui()
        self.transfer = FileTransfer()
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)
        
    def setup_ui(self):
        # 主选项卡
        self.tabs = ttk.Notebook(self.root)
        self.send_tab = ttk.Frame(self.tabs)
        self.recv_tab = ttk.Frame(self.tabs)
        self.tabs.add(self.send_tab, text="发送文件")
        self.tabs.add(self.recv_tab, text="接收文件")
        self.tabs.pack(expand=1, fill="both")

        # 发送界面
        tk.Label(self.send_tab, text="选择文件:").grid(row=0, column=0, padx=5, pady=5)
        self.send_path = tk.Entry(self.send_tab, width=40)
        self.send_path.grid(row=0, column=1, padx=5, pady=5)
        tk.Button(self.send_tab, text="浏览", command=self.browse_file).grid(row=0, column=2, padx=5, pady=5)
        
        tk.Label(self.send_tab, text="本机IP:").grid(row=1, column=0, padx=5, pady=5)
        self.local_ip = tk.Label(self.send_tab, text=self.get_local_ip())
        self.local_ip.grid(row=1, column=1, sticky="w", padx=5, pady=5)
        
        tk.Label(self.send_tab, text="端口:").grid(row=2, column=0, padx=5, pady=5)
        self.port_entry = tk.Entry(self.send_tab, width=10)
        self.port_entry.insert(0, "5000")
        self.port_entry.grid(row=2, column=1, sticky="w", padx=5, pady=5)
        
        self.send_btn = tk.Button(self.send_tab, text="开始发送", command=self.start_send)
        self.send_btn.grid(row=3, column=1, pady=10)
        
        self.send_progress = ttk.Progressbar(self.send_tab, orient="horizontal", length=300, mode="determinate")
        self.send_progress.grid(row=4, column=0, columnspan=3, pady=10)
        self.status_label = tk.Label(self.send_tab, text="准备就绪")
        self.status_label.grid(row=5, column=0, columnspan=3)

        # 接收界面
        tk.Label(self.recv_tab, text="发送方IP:").grid(row=0, column=0, padx=5, pady=5)
        self.recv_ip = tk.Entry(self.recv_tab, width=20)
        self.recv_ip.grid(row=0, column=1, sticky="w", padx=5, pady=5)
        
        tk.Label(self.recv_tab, text="保存路径:").grid(row=1, column=0, padx=5, pady=5)
        self.save_path = tk.Entry(self.recv_tab, width=40)
        self.save_path.grid(row=1, column=1, padx=5, pady=5)
        tk.Button(self.recv_tab, text="浏览", command=self.browse_save).grid(row=1, column=2, padx=5, pady=5)
        
        tk.Label(self.recv_tab, text="端口:").grid(row=2, column=0, padx=5, pady=5)
        self.recv_port = tk.Entry(self.recv_tab, width=10)
        self.recv_port.insert(0, "5000")
        self.recv_port.grid(row=2, column=1, sticky="w", padx=5, pady=5)
        
        self.recv_btn = tk.Button(self.recv_tab, text="开始接收", command=self.start_recv)
        self.recv_btn.grid(row=3, column=1, pady=10)
        
        self.recv_progress = ttk.Progressbar(self.recv_tab, orient="horizontal", length=300, mode="determinate")
        self.recv_progress.grid(row=4, column=0, columnspan=3, pady=10)
        self.recv_status = tk.Label(self.recv_tab, text="等待连接...")
        self.recv_status.grid(row=5, column=0, columnspan=3)

    def browse_file(self):
        path = filedialog.askopenfilename()
        if path:
            self.send_path.delete(0, tk.END)
            self.send_path.insert(0, path)
            self.send_progress["maximum"] = os.path.getsize(path)

    def browse_save(self):
        path = filedialog.asksaveasfilename()
        if path:
            self.save_path.delete(0, tk.END)
            self.save_path.insert(0, path)

    def start_send(self):
        file_path = self.send_path.get()
        if not os.path.exists(file_path):
            messagebox.showerror("错误", "文件不存在!")
            return
            
        port = int(self.port_entry.get())
        threading.Thread(target=self.transfer.send_file, 
                        args=(file_path, port, self.update_send_progress),
                        daemon=True).start()
        self.send_btn.config(state="disabled")
        self.status_label.config(text="等待接收方连接...")

    def start_recv(self):
        if not self.save_path.get():
            messagebox.showerror("错误", "请选择保存路径!")
            return
            
        ip = self.recv_ip.get()
        port = int(self.recv_port.get())
        threading.Thread(target=self.transfer.receive_file,
                        args=(ip, port, self.save_path.get(), self.update_recv_progress),
                        daemon=True).start()
        self.recv_btn.config(state="disabled")
        self.recv_status.config(text="正在连接发送方...")

    def update_send_progress(self, sent, total):
        self.send_progress["value"] = sent
        percent = (sent/total)*100
        self.status_label.config(text=f"已发送: {sent/1024/1024:.1f}MB ({percent:.1f}%)")

    def update_recv_progress(self, received, total):
        self.recv_progress["maximum"] = total
        self.recv_progress["value"] = received
        percent = (received/total)*100 if total > 0 else 0
        self.recv_status.config(text=f"已接收: {received/1024/1024:.1f}MB ({percent:.1f}%)")

    def get_local_ip(self):
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.connect(("8.8.8.8", 80))
            ip = s.getsockname()[0]
            s.close()
            return ip
        except:
            return "127.0.0.1"

    def on_close(self):
        self.transfer.stop()
        self.root.destroy()

    def run(self):
        self.root.mainloop()

class FileTransfer:
    def __init__(self):
        self.active = False
        self.current_size = 0
        self.total_size = 0

    def send_file(self, file_path, port, progress_callback):
        self.active = True
        self.total_size = os.path.getsize(file_path)
        
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.bind(('0.0.0.0', port))
        server.listen(1)
        
        conn, addr = server.accept()
        self.current_size = 0
        
        with open(file_path, 'rb') as f:
            while self.active:
                data = f.read(4096)
                if not data:
                    break
                conn.sendall(data)
                self.current_size += len(data)
                progress_callback(self.current_size, self.total_size)
        
        conn.close()
        server.close()

    def receive_file(self, ip, port, save_path, progress_callback):
        self.active = True
        conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        conn.connect((ip, port))
        
        self.current_size = 0
        with open(save_path, 'wb') as f:
            while self.active:
                data = conn.recv(4096)
                if not data:
                    break
                f.write(data)
                self.current_size += len(data)
                progress_callback(self.current_size, 0)  # 总大小未知
        
        conn.close()
        progress_callback(self.current_size, self.current_size)

    def stop(self):
        self.active = False

if __name__ == "__main__":
    app = TransferGUI()
    app.run()
